package cool.taomu.toolkit

import com.google.common.base.Optional
import com.google.inject.AbstractModule
import com.google.inject.Binder
import com.google.inject.Guice
import com.google.inject.Injector
import com.google.inject.Key
import com.google.inject.Module
import com.google.inject.multibindings.OptionalBinder
import com.google.inject.name.Names
import cool.taomu.toolkit.provider.ContextProvider
import java.lang.annotation.Annotation
import java.util.Map
import org.slf4j.LoggerFactory

class TaomuGuice {
	val static LOG = LoggerFactory.getLogger(TaomuGuice);
	public val static JESERY_SERVICELOADER_PACKAGES = "jesery.serviceloader.packages"
	public val static JESERY_PACKAGES = "jesery.packages"

	def static setProperty(Class<?> inter, Class<?> impl) {
		var key = inter.name
		var value = impl.name
		LOG.info("{}==>{}", key, value)
		System.setProperty(key, value);
	}

	def static void setInjectorInstance(Binder binder) {
		LOG.info("绑定injector");
		binder.bind(Context).toProvider(ContextProvider).asEagerSingleton
	}

	def static void setInjectorInstance(Binder binder, String name) {
		LOG.info("绑定injector 到 {}", name);
		binder.bind(Context).annotatedWith(Names.named(name)).toProvider(ContextProvider).asEagerSingleton
	}

	def static bindConstant(Map<String, Object> arg) {
		new AbstractModule() {
			override configure() {
				arg.forEach [ k, v |
					if (v instanceof String) {
						bindConstant().annotatedWith(Names.named(k)).to(v);
					} else if (v instanceof Integer) {
						bindConstant().annotatedWith(Names.named(k)).to(v);
					} else if (v instanceof Long) {
						bindConstant().annotatedWith(Names.named(k)).to(v);
					} else if (v instanceof Boolean) {
						bindConstant().annotatedWith(Names.named(k)).to(v);
					} else if (v instanceof Character) {
						bindConstant().annotatedWith(Names.named(k)).to(v);
					} else if (v instanceof Short) {
						bindConstant().annotatedWith(Names.named(k)).to(v);
					} else if (v instanceof Float) {
						bindConstant().annotatedWith(Names.named(k)).to(v);
					} else if (v instanceof Double) {
						bindConstant().annotatedWith(Names.named(k)).to(v);
					}
				]
			}
		}
	}

	def static createInjector(Class<? extends Module> ... modules) {
		return createInjector(null, modules)
	}

	def static createInjector(TaomuConfigure crypto, Class<? extends Module> ... modules) {
		val m = <Module>newArrayList()
		if (Optional.fromNullable(modules).present) {
			modules.forEach [
				m.add(it.newInstance);
			]
		}
		return createInjector(crypto, m);
	}

	def static createInjector() {
		return createInjector(null, #[])
	}

	def static createInjector(TaomuConfigure crypto) {
		return createInjector(crypto, #[])
	}

	def static createInjector(TaomuConfigure crypto, Module ... modules) {
		var m = <Module>newArrayList(new BaseModule(crypto))
		if (Optional.fromNullable(modules).present) {
			m.addAll(modules);
		}
		return Guice.createInjector(m);
	}

	def static createInjector(Module ... modules) {
		return createInjector(null, modules)
	}

	def static createInjector(TaomuConfigure crypto, Iterable<? extends Module> modules) {
		var m = <Module>newArrayList(new BaseModule(crypto))
		if (modules.size > 0 && Optional.fromNullable(modules).present) {
			m.addAll(modules);
		}
		return Guice.createInjector(m);
	}

	def static createInjector(Iterable<? extends Module> modules) {
		return createInjector(null, modules);
	}

	def static <T> isBinding(Injector injector, Class<T> type, String name) {
		var key = Key.get(type, Names.named(name));
		return injector.getExistingBinding(key) !== null
	}

	def static <T> getInstance(Injector injector, Class<T> type, String name) {
		var key = Key.get(type, Names.named(name));
		return injector.getInstance(key)
	}

	def static <T> binder(Binder binder, Class<T> zlass, Annotation ann) {
		OptionalBinder.newOptionalBinder(binder, Key.get(
			zlass,
			ann
		)).setDefault()
	}

	def static <T> binder(Binder binder, Class<T> zlass) {
		OptionalBinder.newOptionalBinder(
			binder,
			zlass
		).setDefault()
	}
}
